1.2.1 react 基础写法

1.创建 React 组件

  • 1.1 class Component extends React.Component
import React from 'react';

class Component extends React.Component {
    //needs render function
    render() {
        return (
            //return should tell React what the DOM should look like
            //if this component is rendered in the browser
        );
    }
}
1
2
3
4
5
6
7
8
9
10
11
  • 1.2 function
function Component(props) {
    return (
        //return should tell React what the DOM should look like
        //if this component is rendered in the browser
    );
}
1
2
3
4
5
6

2.HelloWorld

import React from 'react';

function HelloWorld(props){
    //function must return something
    return (
        //return should tell React to render Hello World in the browser
    );

    // div
    // <div>Hello World</div>

    // jsx
    // return React.createElement('div', null, 'Hello World');
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • html
<table>
    <thead>
        <th>
            <td>Col</td>
        </th>
    </thead>
    <tbody>
        <tr>
            <td>Cell</td>
        </tr>
    </tbody>
</table>
1
2
3
4
5
6
7
8
9
10
11
12
  • React.createElement
React.createElement('table', null, 
    [
        React.createElement('thead', null, 
            React.createElement('th', null,
                React.createElement('td', null, 'Col')
            )
        ),
        React.createElement('tbody', null, 
            React.createElement('tr', null,
                React.createElement('td', 'null', 'Cell')
            )
        )
    ]
1
2
3
4
5
6
7
8
9
10
11
12
13

3.JSX 中执行 js 代码: 使用 { //javascript code }

function CompanyProfile(props) {
    //ticker and companyProfileInfo stored in a variable
    const ticker = 'APPL';
    const companyProfileInfo = {
        'Company Name': 'Apple Inc.',
        'Exchange': 'Nasdaq',
        'Sector': 'Technology',
        'Industry': 'Computer Hardware',
        'CEO': 'Timothy D. Cook'
    };
    return (
        <div>
            <div>Profile of: {ticker}</div>
            <div>
                {
                    {/*This is javascript code inside the curly braces*/}
                    Object.keys(companyProfileInfo)
                        .map((key, index) => {
                            return <div>{key}: {companyProfileInfo[key]}</div>
                        })
                }
            </div>
        </div>
    )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

注意:一个组件中必须只有一个根标签, 如:

return (
    <div>
        <div>
            <div></div>
        </div>
        <div></div>
    </div>
)
1
2
3
4
5
6
7
8

而不是下面这样:

# 这样写就是错误的
return ( 
    <div></div>
    <div></div>
)
1
2
3
4
5

4.样式写法

  • 4.1 style:
## html 中
<div style="bottom-border: 1px solid green"></div>

## react JSX 中,css 属性驼峰命名
<div style={{ bottomBorder: `1px solid green`}}></div>

1
2
3
4
5
6
  • 4.2 class
## html 中
<div class="container"></div>

## react JSX 中
<div className={"container"}></div>
1
2
3
4
5
  • 4.2.1 多个 class 判断

使用一个小工具 classNames:

使用方法:

import classnames from 'classnames';
classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'
1
2
3
4
5
6
7
8
9
## html 中
<div onclick="clickHandler()"></div>

## react JSX 中
div onClick={function(){ alert('clicked')}}>

function ClickableButton(props){
    //callback function that's called when button is clicked
    const handleClick = () => { alert('Clicked') }
    return (
        <button onClick={handleClick}></button>
    )
}


# Function Binding
class Input extends React.Component {
    constructor(props){
        super(props);
        
        //bind handleChange function to proper this
        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(e){
        this.setState({
            inputValue: e.target.value
        });
    }

    render(){
        return(
            <input onChange={this.handleChange} value={this.state.inputValue}/>
        )
    }
}

# react 向事件处理程序传递参数


<button onClick={this.editRow.bind(this, id)}>Delete Row</button>

editRow(id, e) {

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

5. Props (单向)

父子组件传参数 props, 子组件不能修改 props 中参数

function Children(props) {
    return (
        <div>{props.textToDisplay}</div>
    )
}

function Parent(props) {
    return (
        <Children textToDisplay={'Hello'}></Children>
    )
}
1
2
3
4
5
6
7
8
9
10
11

在多数情况下,组件最好明确定义一个 props 可以接受的数据类型,数据结构,

  • prop-types: facebook/prop-types

    • .isRequired: 如果 PropTypes.string.isRequired, 那就是必选的;如果 PropTypes.string,那就是可选的;

    • defaultProps: 通过赋值特定的 defaultProps 属性为 props 定义默认值

    // 任何东西都可以被渲染:numbers, strings, elements,或者是包含这些类型的数组(或者是片段)。
    optionalNode: PropTypes.node,
    
    // 一个 React 元素。
    optionalElement: PropTypes.element,
    
    // 你也可以声明一个 prop 是类的一个实例。 
    // 使用 JS 的 instanceof 运算符。
    optionalMessage: PropTypes.instanceOf(Message),
    
    // 你可以声明 prop 是特定的值,类似于枚举
    optionalEnum: PropTypes.oneOf(['News', 'Photos']),
    
    // 一个对象可以是多种类型其中之一
    optionalUnion: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number,
      PropTypes.instanceOf(Message)
    ]),
    
    // 一个某种类型的数组
    optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
    
    // 属性值为某种类型的对象
    optionalObjectOf: PropTypes.objectOf(PropTypes.number),
    
    // 一个特定形式的对象
    optionalObjectWithShape: PropTypes.shape({
      color: PropTypes.string,
      fontSize: PropTypes.number
    }),
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32

使用 :

# 安装
yarn add prop-types


# 使用
import React from 'react';
import PropTypes from 'prop-types';

class SoftwareEngineer extends React.Component {
    render(){
        return (...)
    }
}

//defines "propTypes" property in this component
SoftwareEngineer.propTypes = {
    name: PropTypes.string.isRequired, //expects string and is required
    hobbies: PropTypes.arrayOf(PropTypes.string), //expects array of string
    address: PropTypes.shape({
        street: PropTypes.string,
        city: PropTypes.string
    }) //must be an object with 'street' and 'city' fields
}


# 指定 props 的默认值:
class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}

// 指定 props 的默认值:
Greeting.defaultProps = {
  name: 'Stranger'
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

6.state: 组件本身的状态,不和组件的父级或者子级共享

state 只是一个对象

class Component extends React.Component {
    constructor(props){
        super(props);
        this.state = {
            counter: 0 
        }
    }

    render() {
        return <div>{this.state.counter}</div>
    }
}
                {
                    Object.keys(companyProfileInfo)
                        .map((key, index) => {
                            return <div>{key}: {companyProfileInfo[key]}</div>
                        })
                }
            </div>
    )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  • 6.1 状态更新,必须使用 setState

当 state 发生变化时,React 会重新渲染你的组件,
setState 函数的是异步的

this.setState({
    counter: 2
});
1
2
3

为什么setState是异步的?有人再react官网上提过了的issue,Dan Abramov的回复:

  • 保证内部的一致性,因为更新props的机制可以理解成异步的,那么更新state的机制也要理解成异步的

  • 在许多情况下setState()重新渲染的同步效率很低,而异步可以将几个state合并执行,提高效率。

  • 可以利用异步的特性处理很多事情,如果在开始的页面设了一些异步操作,
    然后去跳了路由换了页面,那么原先的页面即使不展示了,还会继续执行那些异步的东西。

  • 6.2 使用当前的 state 值去更新 state,

//If you are using current state value to update the state, always use updater function
console.log(this.state.counter); //prints 0
this.setState((state) => ({ counter: state.counter + 1}) );
this.setState((state) => ({ counter: state.counter + 1}) );
this.setState((state) => ({ counter: state.counter + 1}) );
1
2
3
4
5

state 和 props 主要的区别在于: props 是不可变的,而 state 可以根据与用户交互来改变

7.生命周期方法

哪种方式定义的组件,其组件名都必须是大写

1.componentDidMount 是进行网络调用的正确生命周期方法(使用API​​获取数据),当组件挂载在DOM上时 componentDidMount 只调用一次; 2.可以使用 componentDidUpdate,每次更新组件时都会调用此生命周期方法; 版本17.0的一部分弃用,因此请勿使用它们

componentWillMount
componentWillUpdate
componentWillReceiveProps
1
2
3
class ComponentWithLifecycle extends React.Component {
    constructor(props){
        super(props);
    }

    componentDidMount(){
        //This will be called after the component is mounted to the DOM
    }

    componentDidUpdate(prevProps, prevState){
        //This will be called after the component is updated
        //Remember component can only be updated when the state changes
        //or the props changes
    }

    componentWillUnmount(){
        //This will be called right before this component is unmounted from
        //the DOM
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

参考